<?php

namespace App\Http\Middleware;

use App\Enums\Kms\UserErrorEnum;
use App\Error\BaseError;
use App\Exceptions\Custom\ResponseHttpException;
use App\Exceptions\KfHttpResponseException;
use App\Models\Kms\User\KmsUser;
use Closure;
use Exception;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
use Illuminate\Validation\UnauthorizedException;
use Kuafu\IpWhite\Service\IpWhiteService;
use Laravel\Passport\Passport;
use Lcobucci\JWT\Parser;

class KmsAuthenticate extends Middleware
{
    // ip白名单模块的应用类型
    const IP_WHITE_TYPE_KMS = 'kms';

    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($request, $guards);

        return $next($request);
    }

    /**
     * Determine if the user is logged in to any of the given guards.
     *
     * @param Request $request
     * @param array $guards
     * @return void
     * @throws Exception
     */
    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }

        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                $clientId = (new Parser())->parse($request->bearerToken())->getClaim("aud");
                if (Passport::clientModel()::where("id", $clientId)->where("name", "kms")->first()) {
                    $rmsUserId = $this->auth->guard($guard)->user()->rmsUserId;
                    $userMap   = KmsUser::query()->where("rmsUserId", $rmsUserId)->get();
                    if ($userMap->where("isExited", 0)->count() == 0) {
                        throw new ResponseHttpException(UserErrorEnum::$USER_EXITED);
                    }

                    $type = self::IP_WHITE_TYPE_KMS;
                    $ip   = (new Parser())->parse($request->bearerToken())->getClaim("ip") ?? '';

                    $check = (new IpWhiteService($rmsUserId, $type, $request))->checkIp($ip, false);
                    if (!$check) {
                        throw new ResponseHttpException(IpWhiteService::ERR_RESPONSE_CODE, null,
                            '已在其他设备登录，请退出后重新登录');
                    }

                    return $this->auth->shouldUse($guard);
                }
            }
        }

        $this->unauthenticated($request, $guards);
    }

    /**
     * @param Request $request
     * @param array $guards
     */
    protected function unauthenticated($request, array $guards)
    {
        throw new KfHttpResponseException(BaseError::UNAUTHORIZED);
    }

}
